package net.cyue.simple.container.util;

import net.cyue.loader.CacheClassLoader;

import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;

/**
 * 扫描并处理指定注解的工具类
 */
public class AnnotationScanner {

    private static final Logger LOGGER = Logger.getLogger(AnnotationScanner.class.getName());
    static {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        if (!(cl instanceof CacheClassLoader)) {
            Thread.currentThread().setContextClassLoader(new CacheClassLoader(cl));
        }
    }

    /**
     * 扫描指定包及其子包中所有带有特定注解的类
     * @param basePackage 基础包名
     * @param annotationClass 要扫描的注解类
     * @return 带有指定注解的类集合
     */
    public static List<Class<?>> scan(String basePackage, Class<?> annotationClass) {
        List<Class<?>> result = new ArrayList<>();

        try {
            // 将包名转换为路径
            String packagePath = basePackage.replace('.', '/');

            // 获取所有资源
            Enumeration<URL> resources = Thread.currentThread()
                    .getContextClassLoader()
                    .getResources(packagePath);

            while (resources.hasMoreElements()) {
                URL resource = resources.nextElement();
                String protocol = resource.getProtocol();

                if ("file".equals(protocol)) {
                    // 处理文件系统中的类
                    String filePath = URLDecoder.decode(resource.getFile(), StandardCharsets.UTF_8.name());
                    findAndProcessClassesInFileSystem(basePackage, filePath, annotationClass, result);
                } else if ("jar".equals(protocol)) {
                    // 处理JAR文件中的类
                    processJarFile(resource, packagePath, annotationClass, result);
                }
            }
        } catch (IOException | URISyntaxException | ClassNotFoundException e) {
            LOGGER.warning(e.getMessage());
            e.printStackTrace();
        }

        return result;
    }

    /**
     * 处理文件系统中的类
     */
    private static void findAndProcessClassesInFileSystem(
        String packageName,
        String packagePath,
        Class<?> annotationClass,
        List<Class<?>> result
    ) throws ClassNotFoundException {
        File dir = new File(packagePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }

        // 查找所有类文件和子目录
        File[] files = dir.listFiles(file ->
            (file.isDirectory()) || (file.getName().endsWith(".class"))
        );

        if (files == null) {
            return;
        }

        for (File file : files) {
            if (file.isDirectory()) {
                // 递归处理子目录
                findAndProcessClassesInFileSystem(
                    packageName + "." + file.getName(),
                    file.getAbsolutePath(),
                    annotationClass,
                    result
                );
            } else {
                // 处理类文件
                String className = file.getName().substring(0, file.getName().length() - 6);
                String fullClassName = packageName + "." + className;

                processClass(fullClassName, annotationClass, result);
            }
        }
    }

    /**
     * 处理JAR文件中的类
     */
    private static void processJarFile(
        URL resource,
        String packagePath,
        Class<?> annotationClass,
        List<Class<?>> result
    ) throws IOException, URISyntaxException, ClassNotFoundException {
        String jarPath = resource.getFile().substring(5, resource.getFile().indexOf("!"));
        JarFile jar = new JarFile(URLDecoder.decode(jarPath, StandardCharsets.UTF_8.name()));

        Enumeration<JarEntry> entries = jar.entries();
        while (entries.hasMoreElements()) {
            JarEntry entry = entries.nextElement();
            String entryName = entry.getName();

            if (entryName.startsWith(packagePath) && entryName.endsWith(".class") && !entry.isDirectory()) {
                // 转换为类名
                String className = entryName.substring(0, entryName.length() - 6).replace('/', '.');
                processClass(className, annotationClass, result);
            }
        }
        jar.close();
    }

    /**
     * 检查类是否带有指定注解，如果有则添加到结果列表
     */
    private static void processClass(
        String className,
        Class<?> annotationClass,
        List<Class<?>> result
    ) throws ClassNotFoundException {
        Class<?> clazz = Thread.currentThread()
                .getContextClassLoader()
                .loadClass(className);
        if (clazz.isAnnotationPresent((Class<? extends java.lang.annotation.Annotation>) annotationClass)) {
            result.add(clazz);
        }
    }
}
